/*
 * param_lib.h
 *
 *  Created on: Oct 8, 2013
 *      Author: filipe
 */

#ifndef PARAM_LIB_H_
#define PARAM_LIB_H_

#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <typeinfo>

using namespace std;

/**
 *
 * TODO: Criar uma abtract class Strategy que tenha os metodos de read, write, gettypeid e gettype. Essa
 * classe sera herdada por FloatStrategy, IntStrategy... Com isso, ao inves de ter um monte de ifs para
 * testar o tipo do dado, isso sera feito em um for. Devera existir um vector de strategy classes registradas
 * e cada Param devera ter uma referencia para a StrategyClass que sabe cuidar dos seus dados. Isso ira facilitar
 * a adicao de novos tipos no arquivo de parametros (basta registrar uma nova strategy) e evitara ter varias
 * herancas de Params que nao tem nada de diferente exceto a forma de lidar com os dados.
 *
 */

class Param
{
	string _name;
	string _type;
	void *_value;

	public:
		Param()
		{
			_value = NULL;
		}

		Param(string name, string type, void *value)
		{
			_name = name;
			_type = type;
			_value = value;
		}

		virtual void set(string name, string type, void *value)
		{
			_name = name;
			_type = type;
			_value = value;
		}

		virtual void setType(string type)
		{
			_type = type;
		}

		virtual void setName(string name)
		{
			_name = name;
		}

		virtual void setValue(void *value)
		{
			_value = value;
		}

		virtual string getType(string)
		{
			return _type;
		}

		virtual string getName()
		{
			return _name;
		}

		virtual void *getValue()
		{
			return _value;
		}

		virtual ~Param()
		{
			if (_value != NULL)
				free(_value);
		}

		virtual void read() = 0;
		virtual void write() = 0;
		virtual string typeId() = 0;
};

class FloatParam : public Param
{
public:

	FloatParam() : Param()
	{
	}

	FloatParam(string name, string type, void *value) : Param(name, type, value)
	{
	}

	virtual void read()
	{
	}

	virtual void write()
	{

	}

	virtual string typeId()
	{
		return string(typeid(float).name());
	}
};


class IntParam : public Param
{
public:

	IntParam() : Param()
	{
	}

	IntParam(string name, string type, void *value) : Param(name, type, value)
	{
	}

	virtual void read()
	{
	}

	virtual void write()
	{

	}

	virtual string typeId()
	{
		return string(typeid(int).name());
	}
};


class StringParam : public Param
{
public:

	StringParam() : Param()
	{
	}

	StringParam(string name, string type, void *value) : Param(name, type, value)
	{
	}

	virtual void read()
	{
	}

	virtual void write()
	{

	}

	virtual string typeId()
	{
		return string(typeid(string).name());
	}
};

class ParamList
{
	public:
		vector<Param*> params;

		template<class T>
		T get(string n)
		{
			T t;

			for (unsigned int i = 0; i < params.size(); i++)
			{
				if (params[i]->getName().compare(n) == 0)
				{
					if (params[i]->typeId().compare(typeid(T).name()) != 0)
						exit(printf("Error: Template class doesn't match type class\n"));

					t = *((T*) params[i]->getValue());
					break;
				}
			}

			return t;
		}

		template<class T>
		void add(string n, string t, T v)
		{
			Param *param;
			T *vcopy = new T;
			(*vcopy) = v;

			if (t.compare("float") == 0)
			{
				param = new FloatParam(n, t, (void*) vcopy);
			}
			else if (t.compare("string") == 0)
			{
				param = new StringParam(n, t, (void*) vcopy);
			}
			else if (t.compare("int") == 0)
			{
				param = new IntParam(n, t, (void*) vcopy);
			}
			else
				exit(printf("Param type not suported: '%s'\n", t.c_str()));

			if (param->typeId().compare(typeid(T).name()) != 0)
				exit(printf("Error: Template class doesn't match type class\n"));

			params.push_back(param);
		}
};

#endif /* PARAM_LIB_H_ */
